/*
 * @(#)HiberDao.java Apr 28, 2007
 * 
 * Copyright 2007 by ChinanetCenter Corporation.
 *
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of
 * ChinanetCenter Corporation ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with ChinanetCenter.
 * 
 */

package com.cnc.bas.db;

import java.io.Serializable;
import java.sql.Connection;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.util.Assert;

import com.cnc.bas.query.PageInfo;
/**
 * 
 * @author 阿闲
 * @date   Apr 30, 2007
 * @version 1.0
 */
public class HiberDao extends HibernateDaoSupport 
	
{
	public static final String BEAN_ID = "hiberDao";
	
	public List selectPages(String hql, int start,int count){
		
		Session session = this.getSession();
		
		Query query = session.createQuery(hql);
		
		query.setFirstResult(start);
		
		query.setMaxResults(count);
		
		List list = query.list();
		
		session.close();
		
		session = null;
		
		return list;
	}
	
    public void load(Object vo, Serializable pk) {
    	getHibernateTemplate().load(vo, pk);   
    	
    }
    
    public Object load(Class voClass, Serializable pk){
    	return (Object)getHibernateTemplate().load(voClass, pk);
    }
    
    public Object load(Class voClass, Serializable pk, LockMode lockMode){
    	return (Object)getHibernateTemplate().load(voClass, pk, lockMode);
    }
	
    public Object get(Class voClass, Serializable pk) {
    	
    	return (Object)getHibernateTemplate().get(voClass, pk);
    }     
	
    public List find(String query) {
    	return getHibernateTemplate().find(query);
    }
    
    public List find(String query, Object param) {
    	return getHibernateTemplate().find(query, param);
    }
    
    public List find(String query, Object[] params) {
    	return getHibernateTemplate().find(query, params);
    }
    
    public void save(Object vo) {
    	getHibernateTemplate().save(vo);
    }

    public void delete(Object vo) {
    	getHibernateTemplate().delete(vo);
    }
   
    public void delete(String query) {
    	getHibernateTemplate().delete(query);
    }
  
    public void deleteAll(Collection voCollection) {
    	getHibernateTemplate().deleteAll(voCollection);
    }    


    public void update(Object vo) {
    	getHibernateTemplate().update(vo);
    }
    
    public void saveOrUpdate(Object vo) {
    	getHibernateTemplate().saveOrUpdate(vo);
    }
    
    //除非特别需要，请不要随便flush
    public void flush(){
    	this.getHibernateTemplate().flush();
    }
    
    public Connection getConnection(){
    	return this.getSession().connection();
    }
    
    /**
     * 按HQL分页查询.
     * 不支持自动获取总结果数,需用户另行执行查询.
     *
     * @param page 分页参数.仅支持pageSize 和firstResult,忽略其他参数.
     * @param hql hql语句.
     * @param values 数量可变的查询参数.
     *
     * @return 分页查询结果,附带结果列表及所有查询时的参数.
     */
    public PageInfo find(final PageInfo page, final String hql, final Map<String, Object> values) {
        Assert.notNull(page, "page不能为空");
        Query q = createQuery(hql, values);
        setPageParameter(q, page);
         List result = q.list();
       
        int totalCount = calculateRecordCount(hql, values);
        page.setTotalCount(totalCount);
        
        page.setPageData(result);
        return page;
    }
    
    /**
     * 根据查询HQL与参数列表创建Query对象.
     * 返回对象类型不是Entity时可用此函数灵活查询.
     *
     * @param values 数量可变的参数
     */
    public Query createQuery(final String queryString, final Object... values) {
        Query query = getSession().createQuery(queryString);
        if (values != null) {
            for (int i = 0; i < values.length; i++) {
                query.setParameter(i, values[i]);
            }
        }
        return query;
    }


    /**
     * 根据查询HQL与参数列表创建Query对象.
     * 返回对象类型不是Entity时可用此函数灵活查询.
     *
     * @param namedParamMap
     */
    public Query createQuery(final String queryString, Map<String, Object> namedParamMap) {
        Assert.hasText(queryString, "queryString不能为空");

        Query query = getSession().createQuery(queryString);
        if (namedParamMap != null && !namedParamMap.isEmpty()) {
            for (Map.Entry<String, Object> entry : namedParamMap.entrySet()) {
                applyNamedParameterToQuery(query, entry.getKey(), entry.getValue());
            }
        }
        return query;
    }
    
    /**
     * @param queryObject
     * @param paramName
     * @param value
     * @throws HibernateException
     */
    private void applyNamedParameterToQuery(Query queryObject, String paramName, Object value)
            throws HibernateException {
        if (value instanceof Collection) {
            queryObject.setParameterList(paramName, (Collection) value);
        } else if (value instanceof Object[]) {
            queryObject.setParameterList(paramName, (Object[]) value);
        } else {
            queryObject.setParameter(paramName, value);
        }
    }
    
    /**
     * @param hql
     * @param args 绑定到HQL中的参数
     * @param argTypes 参数的SQL类型 (即java.sql.Types中定义的常量)
     * 注意：慎用，因为会造成二级缓存和数据库的不一致，使用批量更改或删除，
     * 相当于直接发送一条SQL语句，会绕过Hibernate二级缓存的维护。
     */
    public void execute(final String hql, Object... objs) {
        getHibernateTemplate().bulkUpdate(hql, objs);
    }
    
   
    
    /**
     * 设置分页参数到Query对象,辅助函数.
     */
     protected Query setPageParameter(final Query q, final PageInfo page) {
         q.setFirstResult((int)(page.getCurrentPage()-1)*page.getPageSize());
         q.setMaxResults(page.getPageSize());
         return q;
     }
     
     protected int calculateRecordCount(String hql, Map<String, Object> namedParamMap) {
         String countHql = generateCountStr(hql);
         return uniqueIntResult(countHql, namedParamMap);
     }
     
     /**
      * 截取用于计算记录集总数的HQL语句的起始保留字“from”
      */
     private static final String START_RESERVE_WORDS = "from";
     /**
      * 计算记录集总数的HQL语法前缀
      */
     private static final String SELECT_COUNT_PREFIX = "select count(*) ";
     
     /**
      * 截取用于计算记录集总数的HQL语句的起始保留字数组。
      * 由于这些保留字在HQL语句中均为可选，因此要依次判断HQL语句中是否存在这些保留字。如果发现存在
      * 这些保留字中的任何一个（依次），便确定用于计算记录集总数的HQL语句的结束位置；如果未不存在
      * 这些保留字，则结束位置为原HQL的长度。
      */
     private static final String[] END_RESERVE_WORDS = {" group", " having", " order"};
     
     /**
      * 计算HQL总条数的方法
      * @param hql
      * @return
      */
     public static String generateCountStr(String hql) {
         String lowerCaseHql = hql.toLowerCase();
         int start = lowerCaseHql.indexOf(START_RESERVE_WORDS);
         int end = hql.length();

         //判断是否包含保留字
         for (String key : END_RESERVE_WORDS) {
             if (lowerCaseHql.indexOf(key) > -1) {
                 end = lowerCaseHql.indexOf(key);
                 break;
             }
         }

         return SELECT_COUNT_PREFIX + hql.substring(start, end);
     }
     
     /**
      * 根据named param获取唯一整数结果。
      *
      * @param hql
      * @param namedParamMap
      * @return
      */
     public int uniqueIntResult(String hql, Map<String, Object> namedParamMap) {
         return returnIntValueFromRet(uniqueResult(hql, namedParamMap));
     }
     /**
      * 根据数据库查询结果，返回合适的整数数值。
      *
      * @param obj
      * @return
      */
     private int returnIntValueFromRet(Object obj) {

         if (obj instanceof Long) {
             Long ret = (Long)obj;
             return (ret == null) ? 0 : ret.intValue();
         }

         if (obj instanceof Integer) {
             Integer ret = (Integer)obj;
             return (ret == null) ? 0 : ret.intValue();
         }

         return 0;
     }
    
     /**
      * 根据HQL语句及参数值，获取唯一结果。
      *
      * @param hql
      * @param paramValues
      * @return
      */
     public Object uniqueResult(final String hql, final Map paramValues) {
          Query q = createQuery(hql, paramValues);
          return q.uniqueResult();
     }
}